import json
import load_db_consts
import logging
import random
import time

from db import model
from google.appengine.api import memcache
from google.appengine.ext import db
from model import FacebookData
from model import Student
from model import StudentSession


class StudentClient(object):

  def saveStudent(self, email_address, first_name, middle_name, last_name):
    student = Student(Student.gen_key())
    student.email_address = email_address
    student.first_name = first_name
    student.middle_name = middle_name
    student.last_name = last_name
    student.current_session = model.CURRENT_SESSION
    student.deleted = False
    student.put()
    return student

  def saveStudentSession(self, student_id, dorm, room, ra,
      session=model.CURRENT_SESSION):
    student_session = StudentSession(StudentSession.gen_key())
    student_session.student_id = student_id
    student_session.session = session
    student_session.dorm = dorm
    student_session.room = room
    student_session.ra = ra
    student_session.put()
    return student_session

  def __saveFacebookId(self, student_id, fb_id):
    student = self.getStudent(student_id)
    # Only set the Facebook id for this student if the FB profile is not already
    # set (the Facebook profile is by the actual user so we know it's correct).
    if student and not student.fb_profile:
      student.fb_id = fb_id
      student.put()

  def saveFacebookProfile(self, student_id, fb_profile):
    fb_data = self.getFacebookData(student_id)

    if not fb_data:
      fb_data = FacebookData(FacebookData.gen_key())
      fb_data.session = model.CURRENT_SESSION
      fb_data.student_id = student_id

    fb_data.fb_id = fb_profile['id']
    fb_data.fb_profile = json.dumps(fb_profile)
    fb_data.put()

    # Save FB ID in the student model as well (to display FB photo).
    self.__saveFacebookId(student_id, fb_profile['id'])

  def saveFacebookFriends(self, student_id, fb_friends, fb_matches):
    fb_data = self.getFacebookData(student_id)

    if not fb_data:
      fb_data = FacebookData(FacebookData.gen_key())
      fb_data.session = model.CURRENT_SESSION
      fb_data.student_id = student_id

    fb_data.fb_friends = json.dumps(fb_friends)
    fb_data.fb_matches = json.dumps(fb_matches)
    fb_data.put()

    # Save FB friend counts in the student model.
    self.__saveFacebookFriendCounts(student_id, fb_friends, fb_matches)

    # Update the FB id of each of our matches so that we can display the
    # students picture.
    for fb_match in fb_matches:
      self.__saveFacebookId(fb_match['student_id'], fb_match['fb_id'])

  def __saveFacebookFriendCounts(self, student_id, fb_friends,
      fb_matches):
    student = self.getStudent(student_id)
    student.fb_match_count = len(fb_matches)
    student.fb_friend_count = len(fb_friends)
    student.put()

  def saveStudentConsent(self, student_id, consented):
    student = self.getStudent(student_id)
    student.current_session_data.consented = consented
    student.current_session_data.put()

  def saveStudentStatus(self, student_id, status):
    student = self.getStudent(student_id)
    student.current_session_data.status = status
    student.current_session_data.put()

  def setAdminUser(self, student_id):
    student = self.getStudent(student_id)
    student.admin = True
    student.put()

  def getStudent(self, id):
    return Student.get(Student.gen_key(id))

  def getCurrentSessionData(self, student_id):
    student_session_query = StudentSession.all()
    student_session_query.ancestor(StudentSession.gen_key())
    student_session_query.filter("session = ", model.CURRENT_SESSION)
    student_session_query.filter("student_id = ", student_id)
    return student_session_query.get()

  def getStudentIdForUser(self, user):
    student_id = memcache.get(self.__getStudentIdCacheKey(user.email()))
    if not student_id:
      student = self.getStudentByEmail(user.email())
      if student:
        student_id = student.key().id()
        memcache.set(self.__getStudentIdCacheKey(user.email()), student_id)
    return student_id

  def __getStudentIdCacheKey(self, email_addr):
    return model.CURRENT_SESSION + "-student_id-" + email_addr

  def getStudentByEmail(self, email_address):
    students_query = Student.all()
    students_query.ancestor(Student.gen_key())
    students_query.filter("deleted = ", False)
    students_query.filter("current_session = ", model.CURRENT_SESSION)
    students_query.filter("email_address = ", email_address)
    return students_query.get()

  def getStudents(self, session=None):
    students_query = Student.all()
    students_query.ancestor(Student.gen_key())
    students_query.order('first_name')
    students_query.order('last_name')
    students_query.filter("deleted = ", False)
    if session:
      students_query.filter("current_session = ", session)
    students = students_query.fetch(999999)
    return students

  def getStudentsForWeb(self, use_cache=True):
    if use_cache:
      students_dict = memcache.get(self.__getStudentsCacheKey())
    else:
      students_dict = None

    if students_dict is not None:
      logging.info("*** Got students_web from cache")
      return students_dict
    else:
      students_dict = []
      for student in self.getStudents(model.CURRENT_SESSION):
        # We only need a few fields for each student.  No need to pass
        # everything to the browswer.
        student_dict = {
          'id': student.key().id(),
          'first_name': student.first_name,
          'last_name': student.last_name
        }
        students_dict.append(student_dict)

      if len(students_dict) > 0:
        memcache.set(self.__getStudentsCacheKey(), students_dict, 3600)

      return students_dict

  def __getStudentsCacheKey(self):
    return model.CURRENT_SESSION + "-students_web"

  def getFacebookData(self, student_id):
    fb_data_query = FacebookData.all()
    fb_data_query.ancestor(FacebookData.gen_key())
    fb_data_query.filter("session = ", model.CURRENT_SESSION)
    fb_data_query.filter("student_id = ", student_id)
    return fb_data_query.get()

  def getAllFacebookData(self, session=None):
    fb_data_query = FacebookData.all()
    fb_data_query.ancestor(FacebookData.gen_key())
    if session:
      fb_data_query.filter("session = ", session)
    fb_data = fb_data_query.fetch(999999)
    return fb_data

  def getAllSessionData(self, session=None):
    student_session_query = StudentSession.all()
    student_session_query.ancestor(StudentSession.gen_key())
    if session:
      student_session_query.filter("session = ", session)
    session_data = student_session_query.fetch(999999)
    return session_data

  def deleteAllStudents(self):
    # Clear students from cache.
    memcache.delete(self.__getStudentsCacheKey())

    try:
      while True:
        students_query = Student.all().ancestor(Student.gen_key())
        students_query.filter("current_session = ", model.CURRENT_SESSION)
        students = students_query.fetch(200)
        if len(students) == 0:
          return
        db.delete(students)
        time.sleep(0.5)
    except Exception, e:
      logging.info('*** Could not delete: ' + repr(e))
      pass

  def updateSessionData(self, student, dorm, room, ra, is_new_year=False):
    session_data = self.getCurrentSessionData(student.key().id())
    if not session_data:
      # Create a new session for this student.
      session_data = self.saveStudentSession(student.key().id(), dorm, room, ra)

    if (not is_new_year and
        student.current_session_data and
        student.current_session != session_data.session):
      # Set previous session status in current session.
      session_data.previous_session_status = student.current_session_data.status
      session_data.put()

    # Update student with current session data.
    student.current_session = model.CURRENT_SESSION
    student.current_session_data = session_data
    student.put()

  def loadStudents(self, is_new_year=False):
    student_map = {}
    for student in self.getStudents():
      student_map[student.email_address] = student

    for student_dict in load_db_consts.STUDENTS:
      # Set any missing student data.
      if not student_dict.has_key('middle_name'):
        student_dict['middle_name'] = ''
      if not student_dict.has_key('room'):
        student_dict['room'] = ''
    
      if not student_map.has_key(student_dict['email']):
        # Add new student.
        student = self.saveStudent(student_dict['email'],
            student_dict['first_name'], student_dict['middle_name'],
            student_dict['last_name'])
      else:
        student = student_map[student_dict['email']]
    
      # Update this student with current session data.
      self.updateSessionData(student, student_dict['dorm'],
          student_dict['room'], student_dict['ra'], is_new_year=is_new_year)
